package com.engine.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.engine.core.dao.CodeCustomQueryMapper;
import com.engine.core.dao.CodeResourceMapper;
import com.engine.core.domain.CustomQuery;
import com.engine.core.domain.GenTable;
import com.engine.core.gen.Global;
import com.engine.core.interceptor.JdbcCommandContext;
import com.engine.core.interceptor.ResponseCommand;
import com.engine.core.util.QueryUtil;
import com.engine.core.util.Response;
import com.engine.core.util.Utils;
import com.engine.dialect.DialectType;
import com.engine.query.cmd.QueryResourceCommand;
import com.engine.system.User;
import com.engine.update.cmd.SaveMultiCommand;
import com.engine.update.cmd.SaveOrUpdateCommad;
import com.engine.update.cmd.UpdateMultiCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class CustomService {

    @Autowired
    private CodeCustomQueryMapper codeCustomQueryMapper;

    @Autowired
    private Global global;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private CodeResourceMapper codeResourceMapper;

    public Response queryById(CustomQuery customQuery, User user, Map<String, Object> params) {
        try {
            String action = customQuery.getAction();
            String paramJson = customQuery.getParamJson();
            String columnJson = customQuery.getColumnJson();
            String groupJson = customQuery.getGroupJson();
            String orderJson = customQuery.getOrderJson();
            String whereJson = customQuery.getWhereJson();
            String havingJson = customQuery.getHavingJson();
            int resourceId = customQuery.getResourceId();

            JSONObject parameters = paramJson != null && paramJson.trim().length() > 0 ? JSON.parseObject(paramJson) : new JSONObject();

            Iterator<Map.Entry<String, Object>> paramsIterator = params.entrySet().iterator();
            while (paramsIterator.hasNext()) {
                Map.Entry<String, Object> paramsEntry = paramsIterator.next();
                if (parameters.containsKey(paramsEntry.getKey())) {
                    Object value = parameters.get(paramsEntry.getKey());
                    if (value instanceof JSONObject) {
                        JSONObject jo = (JSONObject) value;
                        jo.put("value", paramsEntry.getValue());
                        parameters.put("value", jo);
                    } else {
                        parameters.put(paramsEntry.getKey(), paramsEntry.getValue());
                    }
                } else {
                    parameters.put(paramsEntry.getKey(), paramsEntry.getValue());
                }
            }


            Map<String, Object> newParams = new HashMap<>();
            JSONObject rootParams = new JSONObject();
            rootParams.put(QueryUtil.QUERY_COLUMNS, columnJson);
            rootParams.put(QueryUtil.QUERY_GROUPBY, groupJson);
            rootParams.put(QueryUtil.QUERY_ORDERBY, orderJson);
            rootParams.put(QueryUtil.QUERY_WHERE, whereJson);
            rootParams.put(QueryUtil.QUERY_HAVING, havingJson);
            rootParams.put(QueryUtil.QUERY_PARAMS, parameters.toJSONString());
            rootParams.put(QueryUtil.QUERY_RESOURCE, resourceId);
            newParams.put(QueryUtil.QUERY_CONTENT, rootParams.toJSONString());

            QueryResourceCommand queryResourceCommand = new QueryResourceCommand(user, newParams);
            DialectType dialectType = (DialectType) DialectType.newInstance(global.getDbType());
            JdbcCommandContext jdbcCommandContext = new JdbcCommandContext(global, jdbcTemplate, applicationContext, dialectType);
            return queryResourceCommand.execute(jdbcCommandContext);
        } catch (Exception e) {
            return Response.static_fail("执行失败！", 0).setErr(e);
        }
    }

    public Response saveOrUpdateById(CustomQuery customUpdate, User user, Map<String, Object> params) {
        try {
            DialectType dialectType = (DialectType) DialectType.newInstance(global.getDbType());
            int resourceId = customUpdate.getResourceId();
            JdbcCommandContext jdbcCommandContext = new JdbcCommandContext(global, jdbcTemplate, applicationContext, dialectType);
            ResponseCommand responseCommand=null;
            Map<String,Object> newParams=new HashMap<>();
            JSONObject rootParams = new JSONObject();

            if(params.containsKey(QueryUtil.UPDATA_IS_BATCH)){
                newParams.put(QueryUtil.UPDATA_IS_BATCH,params.get(QueryUtil.UPDATA_IS_BATCH));
            }
            List<String> noSaveParams=Arrays.asList(QueryUtil.UPDATA_IS_BATCH);
            JSONArray dataArray=new JSONArray();
            if(!params.containsKey(QueryUtil.QUERY_CONTENT) || ((String)params.get(QueryUtil.QUERY_CONTENT)).length()==0){
                JSONObject jo=new JSONObject();
                for(Map.Entry<String,Object> entry:params.entrySet()){
                    if(!noSaveParams.contains(entry.getKey())){
                        jo.put(entry.getKey(),entry.getValue());
                    }
                }
                dataArray.add(jo);
            }else{
                if(JSON.isValidArray((String)params.get(QueryUtil.QUERY_CONTENT))){
                    dataArray.addAll(JSON.parseArray((String)params.get(QueryUtil.QUERY_CONTENT)));
                }else if(JSON.isValidObject((String)params.get(QueryUtil.QUERY_CONTENT))){
                    dataArray.add(JSON.parseObject((String)params.get(QueryUtil.QUERY_CONTENT)));
                }
            }
            rootParams.put(QueryUtil.QUERY_RESOURCE, resourceId);
            rootParams.put(QueryUtil.QUERY_COLUMNS, customUpdate.getColumnJson());
            rootParams.put(QueryUtil.UPDATA_DATA,dataArray.toJSONString());

            switch (customUpdate.getAction()){
                case "save":{
                    newParams.put(QueryUtil.QUERY_CONTENT, rootParams.toJSONString());
                    responseCommand=new SaveMultiCommand(user,newParams);
                    break;
                }
                case "update":{
                    rootParams.put(QueryUtil.QUERY_WHERE, customUpdate.getWhereJson());
                    newParams.put(QueryUtil.QUERY_CONTENT, rootParams.toJSONString());
                    responseCommand=new UpdateMultiCommand(user,newParams);
                    break;
                }
                case "saveOrUpdate":{
                    rootParams.put(QueryUtil.QUERY_WHERE, customUpdate.getWhereJson());
                    newParams.put(QueryUtil.QUERY_CONTENT, rootParams.toJSONString());
                    responseCommand=new SaveOrUpdateCommad(user,newParams);
                    break;
                }
                default:{
                    return Response.static_fail("执行失败！未知的action:"+customUpdate.getAction(), -1);
                }
            }
            return responseCommand.execute(jdbcCommandContext);
        } catch (Exception e) {
            return Response.static_fail("执行失败！", 0).setErr(e);
        }
    }

    public CustomQuery getCustomQuery(int queryId,String resourceName, String resourceNamespace){
         if(queryId>-1){
             return codeCustomQueryMapper.getCustomQuery(queryId);
         }else if(resourceName!=null && resourceName.length()>0
                  && resourceNamespace!=null && resourceNamespace.length()>0){
             return codeCustomQueryMapper.selectByName(resourceName,resourceNamespace);
         }else{
             return null;
         }
    }

    public Response customBasicBuild(String tableName){
        int resourceId=codeResourceMapper.getIdByName(tableName);
        GenTable genTable=codeResourceMapper.getGenTable(Utils.getInt(resourceId,-1));
        List<String> columns=genTable.getColumns().stream().filter(s->!s.isPk()).map(s->s.getColumnName()).collect(Collectors.toList());
        String pkName=genTable.getPkColumn().getColumnName();
        CustomQueryBuilder customQueryBuilder = new CustomQueryBuilder("save",resourceId,"save",genTable.getResourceName());
        customQueryBuilder.setColumns(pkName,columns);
        customQueryBuilder.insertBasic(codeCustomQueryMapper);


        customQueryBuilder = new CustomQueryBuilder("update",resourceId,"update",genTable.getResourceName());
        customQueryBuilder.setColumns(pkName,columns);
        customQueryBuilder.insertBasic(codeCustomQueryMapper);


        customQueryBuilder = new CustomQueryBuilder("saveOrUpdate",resourceId,"saveOrUpdate",genTable.getResourceName());
        customQueryBuilder.setColumns(pkName,columns);
        customQueryBuilder.insertBasic(codeCustomQueryMapper);


        customQueryBuilder = new CustomQueryBuilder("",resourceId,"getById",genTable.getResourceName());
        customQueryBuilder.setColumns(pkName,columns);
        customQueryBuilder.insertBasic(codeCustomQueryMapper);

        return Response.static_success("执行成功");
    }

    public static class CustomQueryBuilder extends CustomQuery {

        private List<String> columns;

        private String pkName;

        public CustomQueryBuilder(String action, int resourceId, String resourceName, String resourceNamespace) {
            this.action = action;
            this.resourceId = resourceId;
            this.resourceName = resourceName;
            this.resourceNamespace = resourceNamespace;
        }

        public void setColumns(String pkName,List<String> columns){
            this.columns=columns;
            this.pkName=pkName;
        }

        public Response insertBasic(CodeCustomQueryMapper codeCustomQueryMapper){
            switch (this.getAction()){
                case "save":{
                    this.setColumnJson(Utils.getArrayStr(columns));
                    break;
                }
                case "update":{
                    this.setColumnJson(Utils.getArrayStr(columns));
                    this.setWhereJson(Utils.getArrayStr(Arrays.asList(pkName)));
                    break;
                }
                case "saveOrUpdate":{
                    this.setColumnJson(Utils.getArrayStr(columns));
                    this.setWhereJson(Utils.getArrayStr(Arrays.asList(pkName)));
                    break;
                }
                case "getById":{
                    this.setColumnJson(Utils.getArrayStr(columns));
                    JSONArray whereJson=new JSONArray();
                    JSONObject jo=new JSONObject();
                    jo.put("column",pkName);
                    jo.put("paramName",pkName);
                    jo.put("qtype","eq");
                    whereJson.add(jo);
                    this.setWhereJson(whereJson.toJSONString());
                    break;
                }
                default:{
                    return Response.static_fail("执行失败！未知的action:"+this.getAction(), -1);
                }
            }
            codeCustomQueryMapper.deleteByName(this.resourceName,this.resourceNamespace);
           int rows=codeCustomQueryMapper.insertCustomQuery(this);
            return Response.static_success("执行成功");
        }

    }
}
